package serialize;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import org.json.JSONException;
import utils.Log;

import java.util.*;

public class GsonTest {

    enum ContentType {
        @SerializedName("0")
        ImageText(0),

        @SerializedName("1")
        Video(1);
        public int value;

        ContentType(int value) {
            this.value = value;
        }

        public Integer getValue() {
            return value;
        }


        public static ContentType fromInteger(Integer value) {
            for (ContentType enumValue : ContentType.values()) {
                if (enumValue.getValue().equals(value)) {
                    return enumValue;
                }
            }
            return null;
        }
    }

    static class BaseModel {
        private int x;
        String y;
        Number z = Number.B;
        private Integer contentType = 0;

        BaseModel(int x, String y) {
            this.x = x;
            this.y = y;
        }

        public String getContentType1() {
            return "ss";
        }

        public void setContentType(ContentType contentType) {
            this.contentType = contentType.value;
        }

        @Override
        public String toString() {
            return "BaseModel{" +
                    "x=" + x +
                    ", y='" + y + '\'' +
                    ", z=" + z +
                    ", contentType=" + getContentType1() +
                    '}';
        }
    }

    static class ExposeModel {

        // refs: https://sites.google.com/site/gson/gson-user-guide#TOC-Finer-Points-with-Objects
        @Expose(serialize = false)
        transient String request;

        @Expose
        String response;

        @Expose
        transient String response2;

        BaseModel baseModel = null;

        Boolean bigB = null;

        boolean smallB;
    }

    enum Number {
        A(1),B(2),C(3);
        int v;

        Number(int x) {
            v = x;
        }
    }

    public static void main(String[] args) {
        BaseModel base = new BaseModel(1, "2");
        String str = new Gson().toJson(base);
        Log.vn(str);

        str = "{\"x\":1,\"y\":\"2\",\"z\":\"B\",\"contentType\":1}";
        BaseModel base2 = new Gson().fromJson(str, BaseModel.class);
        Log.vn(base2.toString());

        base2.y = "base2";

        /** ArrayList */
        List<BaseModel> modelList = new ArrayList<>();
        modelList.add(base);
        modelList.add(base2);
        str = new Gson().toJson(modelList);
        Log.vn(str);
        Log.vn("fromJson==>>");
        List<BaseModel> modelList2 = new Gson().fromJson(str, new TypeToken<List<BaseModel>>() {}.getType());
        Log.vn(modelList2);

        /** HashMap */
        Map<String, BaseModel> modelMap = new HashMap<>();
        modelMap.put("1", base);
        modelMap.put("2", base2);
        str = new Gson().toJson(modelMap);
        Log.vn(str);
        Log.vn("fromJson==>>");
        Map<String, BaseModel> modelMap2 = new Gson().fromJson(str, new TypeToken<Map<String, BaseModel>>() {}.getType());
        Log.vn(modelMap2.toString());


        /** LinkedList */
        List<BaseModel> linkList = new LinkedList<>();
        linkList.add(base);
        linkList.add(base2);
        str = new Gson().toJson(linkList);
        Log.vn(str);
        Log.vn("fromJson==>>");
        List<BaseModel> linkList2 = new Gson().fromJson(str, new TypeToken<List<BaseModel>>() {}.getType());
        Log.vn(linkList2.toString());

        Number a = Number.A;
        str = new Gson().toJson(a);
        Log.vn(str);
        Log.vn("fromJson==>>");
        Number b = new Gson().fromJson(str, new TypeToken<Number>() {}.getType());
        if (b == a) {
            Log.vn("true");
        } else {
            Log.vn("false");
        }


        String kk = "{\"msg_id\":\"KickOut_w26NhKj5_1234\",\"content\":\"{\\\"head\\\":{\\\"businessType\\\":\\\"AppControl\\\",\\\"msgType\\\":\\\"KickOut\\\",\\\"sequence\\\":1234,\\\"timeStamp\\\":1537965477171,\\\"version\\\":null,\\\"delay\\\":0,\\\"extension\\\":null},\\\"body\\\":\\\"{\\\\\\\"kickPddId\\\\\\\":\\\\\\\"w26NhKj5\\\\\\\",\\\\n        \\\\\\\"userID\\\\\\\":17079,\\\\n        \\\\\\\"deviceName\\\\\\\":\\\\\\\"\\u4E09\\u661FC5\\\\\\\"}\\\"}\"}";
        KickAccountModel model = fromJson(kk);


        ExposeModel exposeModel = new ExposeModel();
        exposeModel.request = "json";
        exposeModel.response = "empty";
        exposeModel.response2 = "empty2";
        // https://stackoverflow.com/questions/4802887/gson-how-to-exclude-specific-fields-from-serialization-without-annotations
        Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
        str = gson.toJson(exposeModel);
        Log.vn(str);

        Log.vn(new Gson().toJson(exposeModel));
        exposeModel.baseModel = base;
        Log.vn(new Gson().toJson(exposeModel));


        ContentType contentType = ContentType.ImageText;
        str = gson.toJson(contentType);
        Log.vn(str);


        String resp = "{\"success\":true,\"errorCode\":1000000,\"errorMsg\":null,\"result\":{\"total\":1,\"result\":[{\"id\":139892,\"time\":\"2018-11-22 11:25:42\",\"number\":100,\"type\":1,\"amount\":250,\"status\":1,\"payType\":0,\"createTime\":\"2018-11-22 11:25:42\"}]}}";
        TransactionRecordResp recordResp = fromJson(resp, TransactionRecordResp.class);
        Log.vn(recordResp);
    }

    public static <T> T fromJson(String s, Class<T> c) {
        T bean = null;
        if (c != null && s != null) {
            try {
                bean = new Gson().fromJson(s, c);
            } catch (JsonSyntaxException e) {
                e.printStackTrace();
                try {
                    /**
                     * 如果有默认的无参构造函数，则返回值不为空
                     */
                    bean = c.newInstance();
                } catch (InstantiationException e1) {
                    e1.printStackTrace();
                } catch (IllegalAccessException e1) {
                    e1.printStackTrace();
                }
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
        return bean;
    }

    static KickAccountModel fromJson(String str) {
        if (str == null) {
            return null;
        }

        try {
            KickAccountWrapperModel wrapperModel = new Gson().fromJson(str,
                    new TypeToken<KickAccountWrapperModel>() {}.getType());
//            if (wrapperModel != null) {
//                return wrapperModel.getContent();
//            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    static class KickAccountWrapperModel {
        @SerializedName("msg_id")
        String msgId;

        // KickAccountModel content;

        public String getMsgId() {
            return msgId;
        }

        public void setMsgId(String msgId) {
            this.msgId = msgId;
        }

//        public KickAccountModel getContent() {
//            return content;
//        }
//
//        public void setContent(KickAccountModel content) {
//            this.content = content;
//        }
    }

}
